<!--
Copyright 2013 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<!DOCTYPE html><meta charset="UTF-8">
<style>
  div.anim {
    left: 100px;
    top: 200px;
  }
</style>

<div id="elem"></div>

<div id="anim0" class="anim"></div>
<div id="anim1" class="anim"></div>
<div id="anim2" class="anim"></div>
<div id="anim3" class="anim"></div>
<div id="anim4" class="anim"></div>
<div id="anim5" class="anim"></div>
<div id="anim6" class="anim"></div>
<div id="anim7" class="anim"></div>
<div id="anim8" class="anim"></div>
<div id="anim9" class="anim"></div>
<div id="anim10" class="anim"></div>
<div id="anim11" class="anim"></div>

<script src="../bootstrap.js"></script>
<script>
"use strict";

var keyframes = [{left: "200px"}, {left: "300px"}];

test(function() {
  assert_true(new Animation(document.getElementById("elem"), keyframes).effect
      instanceof KeyframeEffect);
}, "Animation.effect should be an instance of KeyframeEffect when " +
    "created with a keyframe dictionary");

test(function() {
  assert_equals(new KeyframeEffect(keyframes).composite, "replace");
}, "KeyframeEffect.composite should default to 'replace'");

test(function() {
  var effect = new KeyframeEffect(keyframes);
  effect.composite = "foo";
  assert_equals(effect.composite, "replace");
  effect.composite = 42;
  assert_equals(effect.composite, "replace");
  effect.composite = "add";
  assert_equals(effect.composite, "add");
}, "KeyframeEffect.composite should only accept valid values");

timing_test(function() {
  var animation = new Animation(document.getElementById("anim1"), keyframes, 1);
  document.timeline.play(animation);
  at(0.5, function() {
    assert_styles("#anim1", {left: "250px"});
    animation.effect.composite = "add";
    assert_styles("#anim1", {left: "350px"});
  });
}, "Setting KeyframeEffect.composite should cause immediate update");

test(function() {
  var frames = new KeyframeEffect(
      [{left: "100px"}, {top: "200px"}]).getFrames();
  assert_equals(frames.length, 2);
  assert_equals(frames[0].left, "100px");
  assert_equals(frames[1].top, "200px");
}, "KeyframeEffect.getFrames() should return the specified keyframes");

test(function() {
  var frames = new KeyframeEffect({left: "100px"}).getFrames();
  assert_equals(frames.length, 1);
  assert_equals(frames[0].left, "100px");
}, "KeyframeEffect should handle a single keyframe");

test(function() {
  var frames = new KeyframeEffect({}).getFrames();
  assert_equals(frames.length, 1);
  assert_equals(typeof frames[0], "object");
}, "KeyframeEffect should handle an empty keyframe");

test(function() {
  var frames = new KeyframeEffect().getFrames();
  assert_equals(frames.length, 1);
  assert_equals(typeof frames[0], "object");
}, "KeyframeEffect should handle no input for keyframe dictionary");

test(function() {
  var frames = new KeyframeEffect(42).getFrames();
  assert_equals(frames.length, 1);
  assert_equals(typeof frames[0], "object");
}, "KeyframeEffect should handle non-objects for keyframe dictionary");

test(function() {
  assert_false(
      new KeyframeEffect(keyframes).getFrames() === keyframes);
}, "KeyframeEffect.getFrames() should not return the original " +
    "keyframe dictionary");

test(function() {
  var effect = new KeyframeEffect({left: "100px"});
  effect.getFrames().push({top: "200px"});
  var frames = effect.getFrames();
  assert_equals(frames.length, 1);
  assert_equals(frames[0].left, "100px");
  assert_equals(frames[0].top, undefined);
}, "KeyframeEffect.getFrames() should not allow internal state to " +
    "be modified");

test(function() {
  assert_equals(new KeyframeEffect(keyframes).getFrames()[0].offset,
      null);
}, "Default keyframe offset should be null");

test(function() {
  assert_equals(
      new KeyframeEffect({offset: "foo"}).getFrames()[0].offset, null);
  assert_equals(new KeyframeEffect({offset: 42}).getFrames()[0].offset,
      42);
}, "Keyframes should only accept valid values for offset");

test(function() {
  assert_equals(new KeyframeEffect(keyframes).getFrames()[0].composite,
      null);
}, "Default keyframe composite should be null");

test(function() {
  assert_equals(
      new KeyframeEffect({composite: "foo"}).getFrames()[0].composite,
      null);
  assert_equals(
      new KeyframeEffect({composite: 42}).getFrames()[0].composite,
      null);
  assert_equals(
      new KeyframeEffect({composite: "add"}).getFrames()[0].composite,
      "add");
  assert_equals(new KeyframeEffect(
      {composite: "replace"}).getFrames()[0].composite,
      "replace");
}, "Keyframes should only accept valid values for composite");

test(function() {
  assert_equals(new KeyframeEffect({left: null}).getFrames()[0].left,
      "");
}, "Keyframe should handle null property values");

test(function() {
  assert_equals(
      typeof new KeyframeEffect({left: 42}).getFrames()[0].left,
      "string");
  assert_equals(new KeyframeEffect({left: 42}).getFrames()[0].left,
      "42");
  var obj = { toString: function() { return "toString() called"; } };
  assert_equals(new KeyframeEffect({left: obj}).getFrames()[0].left,
      obj.toString());
}, "Keyframe property values should be stringified");

timing_test(function() {
  document.timeline.play(new Animation(
      document.getElementById("anim2"), {left: null, top: ''}, 1));
  at(1.0, function() {
    assert_styles("#anim2", {left: "100px"});
    assert_styles("#anim2", {top: "200px"});
  });
}, "Invalid keyframe property values should be ignored");

test(function() {
  var effect = new KeyframeEffect(keyframes);
  effect.setFrames({top: "200px"});
  var frames = effect.getFrames();
  assert_equals(frames[0].left, undefined);
  assert_equals(frames[0].top, "200px");
}, "KeyframeEffect.setFrames() should replace exisiting keyframes");

timing_test(function() {
  var animation = new Animation(document.getElementById("anim3"), keyframes, 1);
  document.timeline.play(animation);
  at(0.5, function() {
    assert_styles("#anim3", {left: "250px"});
    animation.effect.setFrames([{left: "300px"}, {left: "400px"}]);
    assert_styles("#anim3", {left: "350px"});
  });
}, "KeyframeEffect.setFrames() should immediately update its target");
timing_test(function() {
  document.timeline.play(new Animation(document.getElementById("anim10"), [
    {left: "100px"},
    {left: "200px"},
    {left: "100px"},
    {left: "300px"},
    {left: "100px"},
  ], 1));
  at(0.0, function() {
    assert_styles("#anim10", {left: "100px"});
  });
  at(0.25, function() {
    assert_styles("#anim10", {left: "200px"});
  });
  at(0.5, function() {
    assert_styles("#anim10", {left: "100px"});
  });
  at(0.75, function() {
    assert_styles("#anim10", {left: "300px"});
  });
  at(1.0, function() {
    assert_styles("#anim10", {left: "100px"});
  });
}, "Keyframes should be distributed evenly between offsets 0 and 1");

timing_test(function() {
  document.timeline.play(new Animation(document.getElementById("anim11"), [
    {left: "100px", offset: 0.0},
    {left: "200px", offset: 0.7},
    {left: "100px"},
    {left: "300px"},
    {left: "100px", offset: 1.0},
  ], 1));
  at(0.0, function() {
    assert_styles("#anim11", {left: "100px"});
  });
  at(0.7, function() {
    assert_styles("#anim11", {left: "200px"});
  });
  at(0.8, function() {
    assert_styles("#anim11", {left: "100px"});
  });
  at(0.9, function() {
    assert_styles("#anim11", {left: "300px"});
  });
  at(1.0, function() {
    assert_styles("#anim11", {left: "100px"});
  });
}, "Keyframes should be distributed evenly between keyframes with offsets");

</script>
